﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

#if !(V1_1 || V2 || V3 || V3_5)
using System.Dynamic;
using System.Linq.Expressions;
#endif

namespace V8.Net
{
    // ========================================================================================================================

    /// <summary>
    /// 'V8Function'继承自V8NativeObject,后者为您实现了'DynamicObject',但是如果不需要动态对象,请随意为自己的类实现'IV8Function'接口.
    /// </summary>
    public interface IV8Function : IV8NativeObject
    {
        /// <summary>
        /// 对创建此对象的FunctionTemplate的引用(一旦设置,就永远不要更改!)
        /// 注意:这只是调用'V8Engine.GetObjectTemplate()'.
        /// </summary>
        FunctionTemplate FunctionTemplate { get; }

        /// <summary>
        /// 托管回调引用，在调用javaScript函数时会调用该引用。
        /// 您可以随时动态更新它，甚至可以将其设置为null。
        /// </summary>
        JSFunction Callback { get; set; }

        /// <summary>
        /// 调用本机端以调用与此托管函数包装器关联的函数.
        /// 注意:这只是在不使用函数名的情况下调用'base.Call()'
        /// </summary>
        InternalHandle Call(params InternalHandle[] args);

        /// <summary>
        /// 调用本机端以调用与此托管函数包装器关联的函数. 调用时,'_this'属性是函数内的'this'对象
        /// 注意:这只是在不使用函数名的情况下调用'base.Call()'
        /// </summary>
        InternalHandle Call(InternalHandle _this, params InternalHandle[] args);
    }

    /// <summary>
    /// Represents a basic JavaScript function object.  By default, this object is used for the global environment.
    /// </summary>
    public class V8Function : V8NativeObject, IV8Function
    {
        // --------------------------------------------------------------------------------------------------------------------

        public FunctionTemplate FunctionTemplate { get { return (FunctionTemplate)base.Template; } }

        public JSFunction Callback { get; set; }

        // --------------------------------------------------------------------------------------------------------------------

        public V8Function()
            : base()
        {
        }

        public V8Function(IV8Function proxy)
            : base(proxy)
        {
        }

        // --------------------------------------------------------------------------------------------------------------------

        /// <summary>
        /// Calls the native side to invoke the function associated with this managed function wrapper.
        /// <para>Note: This method simply calls 'Handle.Call()' without a function name.</para>
        /// </summary>
        public InternalHandle Call(params InternalHandle[] args) { return _Handle.Call(null, null, args); }

        /// <summary>
        /// Calls the native side to invoke the function associated with this managed function wrapper.
        /// The '_this' property is the "this" object within the function when called.
        /// <para>Note: This method simply calls 'Handle.Call()' without a function name.</para>
        /// </summary>
        public InternalHandle Call(InternalHandle _this, params InternalHandle[] args) { return _Handle.Call(null, _this, args); }

        /// <summary>
        /// If the function object has a function property in itself (usually considered a static property in theory), you can use this to invoke it.
        /// </summary>
        new public InternalHandle Call(string functionName, InternalHandle _this, params InternalHandle[] args)
        {
            if (functionName.IsNullOrWhiteSpace()) throw new ArgumentNullException("functionName (不能为null，空或仅空格)");
            return _Handle.Call(functionName, _this, args); // (if a function name exists, then it is a request to get a property name on the object as a function [and not to use this function object itself])
        }

        // --------------------------------------------------------------------------------------------------------------------
    }

    // ========================================================================================================================

    /// <summary>
    /// This generic version of 'V8ManagedObject' allows injecting your own class by implementing the 'IV8ManagedObject' interface.
    /// </summary>
    /// <typeparam name="T">Your own class, which implements the 'IV8ManagedObject' interface.  Don't use the generic version if you are able to inherit from 'V8ManagedObject' instead.</typeparam>
    public unsafe class V8Function<T> : V8Function
        where T : IV8Function, new()
    {
        // --------------------------------------------------------------------------------------------------------------------

        public V8Function()
            : base(new T())
        {
        }

        // --------------------------------------------------------------------------------------------------------------------
    }

    // ========================================================================================================================
}
